//package com.lanjiyin.cloud.gate.filter;
//
//
//import java.net.URI;
//import java.nio.CharBuffer;
//import java.nio.charset.StandardCharsets;
//import java.util.Date;
//import java.util.Iterator;
//import java.util.LinkedHashSet;
//import java.util.List;
//import java.util.concurrent.atomic.AtomicReference;
//import java.util.function.Consumer;
//import java.util.regex.Pattern;
//import java.util.stream.Collectors;
//import java.util.stream.Stream;
//
//import org.apache.commons.lang3.StringUtils;
//import org.jetbrains.annotations.NotNull;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
//import org.springframework.cloud.gateway.filter.GlobalFilter;
//import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.context.annotation.Lazy;
//import org.springframework.core.io.buffer.DataBuffer;
//import org.springframework.core.io.buffer.DataBufferUtils;
//import org.springframework.core.io.buffer.NettyDataBufferFactory;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.HttpStatus;
//import org.springframework.http.server.reactive.ServerHttpRequest;
//import org.springframework.web.bind.annotation.RequestMethod;
//import org.springframework.web.server.ServerWebExchange;
//
//import com.alibaba.fastjson.JSONObject;
//import com.lanjiyin.cloud.admin.vo.authority.PermissionInfo;
//import com.lanjiyin.cloud.admin.vo.log.LogInfo;
//import com.lanjiyin.cloud.auth.client.config.UserAuthConfig;
//import com.lanjiyin.cloud.auth.client.jwt.UserAuthUtil;
//import com.lanjiyin.cloud.auth.common.util.jwt.IJWTInfo;
//import com.lanjiyin.cloud.common.context.BaseContextHandler;
//import com.lanjiyin.cloud.common.msg.BaseResponse;
//import com.lanjiyin.cloud.common.msg.auth.TokenErrorResponse;
//import com.lanjiyin.cloud.common.msg.auth.TokenForbiddenResponse;
//import com.lanjiyin.cloud.gate.feign.ILogService;
//import com.lanjiyin.cloud.gate.feign.IUserService;
//import com.lanjiyin.cloud.gate.handler.RequestBodyRoutePredicateFactory;
//import com.lanjiyin.cloud.gate.utils.DBLog;
//
//import io.netty.buffer.ByteBufAllocator;
//import lombok.extern.slf4j.Slf4j;
//import reactor.core.publisher.Flux;
//import reactor.core.publisher.Mono;
//
///**
// * 网关过滤器
// * 
// * @author: JACK.LIN
// * @date: 2020年5月20日 下午2:53:28
// */
//@Configuration
//@Slf4j
//public class AccessGatewayFilter implements GlobalFilter {
//	@Autowired
//	@Lazy
//	private IUserService userService;
////	@Autowired
////	@Lazy
////	private ICompanyAccountService companyAccountService;
////	@Autowired
////	@Lazy
////	private IWorkerAccountService workerAccountService;
//	@Autowired
//	@Lazy
//	private ILogService logService;
////	@Autowired
////	@Lazy
////	private CacheAPI cacheApi;
//
//	@Value("${gate.ignore.startWith}")
//	private String startWith;
//	@Value("${app.filter-uri.company.startWith}")
//	private String companyAppStartWith;
//	@Value("${app.filter-uri.worker.startWith}")
//	private String workerAppStartWith;
//
//	// @Value("${zuul.prefix}")
////    private String zuulPrefix;
//
//	private static final String GATE_WAY_PREFIX = "/api";
//	@Autowired
//	private UserAuthUtil userAuthUtil;
//	@Autowired
//	private UserAuthConfig userAuthConfig;
//
//	@Override
//	public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
////		log.info("check token and user permission....");
//		LinkedHashSet requiredAttribute = serverWebExchange
//				.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
//		ServerHttpRequest request = serverWebExchange.getRequest();
//		String requestUri = request.getPath().pathWithinApplication().value();
//		if (requiredAttribute != null) {
//			Iterator<URI> iterator = requiredAttribute.iterator();
//			while (iterator.hasNext()) {
//				URI next = iterator.next();
//				if (next.getPath().startsWith(GATE_WAY_PREFIX)) {
//					requestUri = next.getPath().substring(GATE_WAY_PREFIX.length());
//				}
//			}
//		}
//		final String method = request.getMethod().toString();
//		BaseContextHandler.setToken(null);
//		ServerHttpRequest.Builder mutate = request.mutate();
//		//防止内部服务被外部调用
//		if(requestUri.toLowerCase().contains("feign")) {
//			log.error("请求地址不合法：FeignUrl："+requestUri);
//			return getVoidMono(serverWebExchange, new TokenErrorResponse("User Token Forbidden or Expired!"));
//		}
//		// 不进行拦截的地址
//		if (isStartWith(requestUri)) {
//			ServerHttpRequest build = mutate.build();
//			return gatewayFilterChain.filter(serverWebExchange.mutate().request(build).build());
//		}
//		// 企业端APP权限校验
//		if (isStartWithByCompanyApp(requestUri)) {
//			// 用户权限校验（通过获取请求头用户token进行校验）
////			log.info("企业端APPToken校验中......");
//			CompanyAccountDto accDto = null;
//			try {
//				accDto = getCompanyAccountUser(request, mutate);
//				if (null == accDto) {
//					log.error("企业用户Token不存在");
//					return getVoidMono(serverWebExchange, new TokenErrorResponse("User Token Forbidden or Expired!"));
//				}
//				String accountID = String.valueOf(accDto.getId());
//				Consumer<HttpHeaders> httpHeaders = httpHeader -> {
//					httpHeader.set("accountID", accountID);
//				};
//				ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest().mutate().headers(httpHeaders)
//						.build();
//				return gatewayFilterChain.filter(serverWebExchange.mutate().request(serverHttpRequest).build());
//			} catch (Exception e) {
//				log.error("企业用户Token过期异常", e);
//				return getVoidMono(serverWebExchange, new TokenErrorResponse("User Token Forbidden or Expired!"));
//			}
//		} // 工人端APP权限校验
//		else if (isStartWithByWorkerApp(requestUri)) {
//			// 用户权限校验（通过获取请求头用户token进行校验）
////			log.info("工头工人端APPToken校验中......");
//			WorkerAccountDto accDto = null;
//			try {
//				accDto = getWorkerAccountUser(request,mutate);
//				if(null == accDto) {
//					log.error("班组长/工人用户Token不存在");
//					return getVoidMono(serverWebExchange, new TokenErrorResponse("User Token Forbidden or Expired!"));
//				}
//				String accountID = String.valueOf(accDto.getId());
//				Consumer<HttpHeaders> httpHeaders = httpHeader -> {
//					httpHeader.set("accountID", accountID);
//				};
//				ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest().mutate().headers(httpHeaders)
//						.build();
//				return gatewayFilterChain.filter(serverWebExchange.mutate().request(serverHttpRequest).build());
//			}catch(Exception e) {
//				log.error("班组长/工人用户Token过期异常", e);
//				return getVoidMono(serverWebExchange, new TokenErrorResponse("User Token Forbidden or Expired!"));
//			}
//		}
//		// 后台权限校验
//		else {
//			IJWTInfo user = null;
//			try {
//				user = getJWTUser(request, mutate);
//			} catch (Exception e) {
//				log.error("后台用户Token过期异常", e);
//				return getVoidMono(serverWebExchange, new TokenErrorResponse("User Token Forbidden or Expired!"));
//			}
//			List<PermissionInfo> permissionIfs = userService.getAllPermissionInfo();
//			// 判断资源是否启用权限约束
//			Stream<PermissionInfo> stream = getPermissionIfs(requestUri, method, permissionIfs);
//			List<PermissionInfo> result = stream.collect(Collectors.toList());
//			PermissionInfo[] permissions = result.toArray(new PermissionInfo[] {});
//			if (permissions.length > 0) {
//				if (checkUserPermission(permissions, serverWebExchange, user)) {
//					return getVoidMono(serverWebExchange,
//							new TokenForbiddenResponse("User Forbidden!Does not has Permission!"));
//				}
//			}
//		}
//		// 申请客户端密钥头
////        mutate.header(serviceAuthConfig.getTokenHeader(), serviceAuthUtil.getClientToken());
//		ServerHttpRequest build = mutate.build();
//		return gatewayFilterChain.filter(serverWebExchange.mutate().request(build).build());
//
//	}
//
//	/**
//	 * 网关抛异常
//	 *
//	 * @param body
//	 */
//	@NotNull
//	private Mono<Void> getVoidMono(ServerWebExchange serverWebExchange, BaseResponse body) {
//		serverWebExchange.getResponse().setStatusCode(HttpStatus.OK);
//		byte[] bytes = JSONObject.toJSONString(body).getBytes(StandardCharsets.UTF_8);
//		DataBuffer buffer = serverWebExchange.getResponse().bufferFactory().wrap(bytes);
//		return serverWebExchange.getResponse().writeWith(Flux.just(buffer));
//	}
//
//	/**
//	 * 获取目标权限资源
//	 *
//	 * @param requestUri
//	 * @param method
//	 * @param serviceInfo
//	 * @return
//	 */
//	private Stream<PermissionInfo> getPermissionIfs(final String requestUri, final String method,
//			List<PermissionInfo> serviceInfo) {
//		return serviceInfo.parallelStream().filter(permissionInfo -> {
//			String uri = permissionInfo.getUri();
//			if (uri.indexOf("{") > 0) {
//				uri = uri.replaceAll("\\{\\*\\}", "[a-zA-Z\\\\d]+");
//			}
//			String regEx = "^" + uri + "$";
//			return (Pattern.compile(regEx).matcher(requestUri).find()) && method.equals(permissionInfo.getMethod());
//		});
//	}
//
//	private void setCurrentUserInfoAndLog(ServerWebExchange serverWebExchange, IJWTInfo user, PermissionInfo pm) {
//		String host = serverWebExchange.getRequest().getRemoteAddress().toString();
//		LogInfo logInfo = new LogInfo(pm.getMenu(), pm.getName(), pm.getUri(), new Date(), user.getId(), user.getName(),
//				host, String.valueOf(
//						serverWebExchange.getAttributes().get(RequestBodyRoutePredicateFactory.REQUEST_BODY_ATTR)));
//		DBLog.getInstance().setLogService(logService).offerQueue(logInfo);
//	}
//
//	/**
//	 * 返回session中的用户信息
//	 *
//	 * @param request
//	 * @param ctx
//	 * @return
//	 */
//	private IJWTInfo getJWTUser(ServerHttpRequest request, ServerHttpRequest.Builder ctx) throws Exception {
//		List<String> strings = request.getHeaders().get(userAuthConfig.getTokenHeader());
//		String authToken = null;
//		if (strings != null) {
//			authToken = strings.get(0);
//		}
//		if (StringUtils.isBlank(authToken)) {
//			strings = request.getQueryParams().get("token");
//			if (strings != null) {
//				authToken = strings.get(0);
//			}
//		}
//		ctx.header(userAuthConfig.getTokenHeader(), authToken);
//		BaseContextHandler.setToken(authToken);
//		IJWTInfo jwtInfo = userAuthUtil.getInfoFromToken(authToken);
//		ctx.header("userName", jwtInfo.getUniqueName());
//		ctx.header("userId", jwtInfo.getId());
//		BaseContextHandler.setUsername(jwtInfo.getUniqueName());
//		BaseContextHandler.setUserID(jwtInfo.getId());
//		BaseContextHandler.setName(jwtInfo.getName());
//		return jwtInfo;
//	}
//
//	/**
//	 * 返回APP的用户信息
//	 *
//	 * @param request
//	 * @param ctx
//	 * @return
//	 */
//	private CompanyAccountDto getCompanyAccountUser(ServerHttpRequest request, ServerHttpRequest.Builder ctx)
//			throws Exception {
//		List<String> strings = request.getHeaders().get(userAuthConfig.getTokenHeader());
//		String accessToken = null;
//		if (strings != null) {
//			accessToken = strings.get(0);
//		}
//		if (StringUtils.isBlank(accessToken)) {
//			return null;
//		}
////		String jsonStr = cacheApi.get("companyaccount:" + accessToken);
////		if (StringUtils.isNotBlank(jsonStr)) {
////			return JSON.toJavaObject(JSON.parseObject(jsonStr), CompanyAccountDto.class);
////		} else {
////			return companyAccountService.getAccount(accessToken);
////		}
//		return companyAccountService.getAccount(accessToken);
//	}
//	/**
//	 * 获取工头工人端APP用户信息
//	 * @param request
//	 * @param ctx
//	 * @return
//	 * @throws Exception      
//	 * CompanyAccountDto
//	 */
//	private WorkerAccountDto getWorkerAccountUser(ServerHttpRequest request, ServerHttpRequest.Builder ctx)
//			throws Exception {
//		List<String> strings = request.getHeaders().get(userAuthConfig.getTokenHeader());
//		String accessToken = null;
//		if (strings != null) {
//			accessToken = strings.get(0);
//		}
//		if (StringUtils.isBlank(accessToken)) {
//			return null;
//		}
//		return workerAccountService.getAccount(accessToken);
//	}
//
//	private boolean checkUserPermission(PermissionInfo[] permissions, ServerWebExchange ctx, IJWTInfo user) {
//		List<PermissionInfo> permissionInfos = userService.getPermissionByUsername(user.getUniqueName());
//		PermissionInfo current = null;
//		for (PermissionInfo info : permissions) {
//			boolean anyMatch = permissionInfos.parallelStream()
//					.anyMatch(permissionInfo -> permissionInfo.getCode().equals(info.getCode()));
//			if (anyMatch) {
//				current = info;
//				break;
//			}
//		}
//		if (current == null) {
//			return true;
//		} else {
//			if (!RequestMethod.GET.toString().equals(current.getMethod())) {
//				setCurrentUserInfoAndLog(ctx, user, current);
//			}
//			return false;
//		}
//	}
//
//	/**
//	 * URI是否以什么打头
//	 *
//	 * @param requestUri
//	 * @return
//	 */
//	private boolean isStartWith(String requestUri) {
//		boolean flag = false;
//		for (String s : startWith.split(",")) {
//			if (requestUri.startsWith(s)) {
//				return true;
//			}
//		}
//		return flag;
//	}
//
//	/**
//	 * 判断企业端请求URI
//	 * 
//	 * @param requestUri
//	 * @return boolean
//	 */
//	private boolean isStartWithByCompanyApp(String requestUri) {
//		boolean flag = false;
//		for (String s : companyAppStartWith.split(",")) {
//			if (requestUri.startsWith(s)) {
//				return true;
//			}
//		}
//		return flag;
//	}
//
//	/**
//	 * 判断工人端请求URI
//	 * 
//	 * @param requestUri
//	 * @return boolean
//	 */
//	private boolean isStartWithByWorkerApp(String requestUri) {
//		boolean flag = false;
//		for (String s : workerAppStartWith.split(",")) {
//			if (requestUri.startsWith(s)) {
//				return true;
//			}
//		}
//		return flag;
//	}
//
//	/**
//	 * 从Flux<DataBuffer>中获取字符串的方法
//	 * 
//	 * @return 请求体
//	 */
//	private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
//		// 获取请求体
//		Flux<DataBuffer> body = serverHttpRequest.getBody();
//
//		AtomicReference<String> bodyRef = new AtomicReference<>();
//		body.subscribe(buffer -> {
//			CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
//			DataBufferUtils.release(buffer);
//			bodyRef.set(charBuffer.toString());
//		});
//		// 获取request body
//		return bodyRef.get();
//	}
//
//	private DataBuffer stringBuffer(String value) {
//		byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
//
//		NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
//		DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
//		buffer.write(bytes);
//		return buffer;
//	}
//
//	/**
//	 * 网关抛异常
//	 *
//	 * @param body
//	 * @param code
//	 */
//	private Mono<Void> setFailedRequest(ServerWebExchange serverWebExchange, String body, int code) {
//		serverWebExchange.getResponse().setStatusCode(HttpStatus.OK);
//		return serverWebExchange.getResponse().setComplete();
//	}
//
//}
